package com.runa.monitor.platinterface.meter3_0;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.runa.monitor.comm.dto.newComm.AsynResult;
import com.runa.monitor.comm.dto.newComm.HotMeterVO;
import com.runa.monitor.comm.dto.newComm.PanelVO;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.monitor.comm.entity.CommPanel;
import com.runa.monitor.comm.enums.NetFaultCode;
import com.runa.monitor.platinterface.backwork.impl.RccTaskFunction;
import com.runa.monitor.platinterface.backwork.impl.SubEquReadTaskFunction;
import com.runa.monitor.platinterface.meter3_0.util.MySqlJdbcUtil;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.mqtt.MqttUtil;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.persistence.cache.CommNetEquipmentCache;
import com.runa.persistence.service.CommNetEquipmentService;
import com.runa.persistence.util.LogUtil;
import com.runa.rccprotocol.dto.equdata.EquData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author diandian
 * @Date 2022/11/22 15:34
 */
@Component
public class HouseEquIDataService {
    private static final Logger logger = LoggerFactory.getLogger(HouseEquIDataService.class);

    @Value("${threePointZero.url:}")
    private String tpzUrl;

    @Value("${threePointZero.username:}")
    private String tpzUsername;

    @Value("${threePointZero.password:}")
    private String tpzPassword;

    private MySqlJdbcUtil mySqlJdbcUtil;

//    private MySqlJdbcUtil mySqlJdbcUtil = new MySqlJdbcUtil(tpzUrl, tpzUsername, tpzPassword);

    public void executeMethod(String netEquNo, EquData.EquDataType type, String equSerial, TaskFunction function) {
        if (mySqlJdbcUtil == null) mySqlJdbcUtil = new MySqlJdbcUtil(tpzUrl, tpzUsername, tpzPassword);
        if (type == EquData.EquDataType.METER) {
            String houseMeterSql = "select da.supplyTemperature,da.returnTemperature,da.reason,da.state,da.planTime,da.readTime,da.equTime,da.flow," +
                    " da.heat,da.accFlow,da.accHeat,da.stateCode, " +
                    " equ.serialNo as equNo,equ.index,ne.serialNo as netNo from rcc_d_housemetercurrentdata da " +
                    "inner join rcc_e_housemeter equ on equ.uniqueId = da.houseMeterId " +
                    " inner join rcc_e_netequ ne on ne.uniqueId = equ.netEquId " +
                    " where ne.serialNo = '" + netEquNo + "' AND equ.serialNo = '" + equSerial + "'";
            logger.info("MeterSql语句为：" + houseMeterSql);
            ArrayList<HashMap<String, Object>> meterDataList = mySqlJdbcUtil.query(houseMeterSql);
            logger.info("meterDataList为：" + JSON.toJSONString(meterDataList));
            Map<String, List<HashMap<String, Object>>> meterByNetNo = meterDataList
                    .stream()
                    .collect(Collectors.groupingBy(v -> String.valueOf(v.get("netNo"))));
            for (Map.Entry<String, List<HashMap<String, Object>>> entry : meterByNetNo.entrySet()) {
                String key = entry.getKey();
                //是否需要对没有网络设备的计量设备处理？因为对接的3.0系统，应该是没有主动上报的设备
                if ("null".equals(key)) {
                    logger.debug("没有找到网络设备编号" + JSONObject.toJSONString(entry.getValue()));
                    continue;
                }
                List<HashMap<String, Object>> valueList = entry.getValue();
                //同一个网络设备下的数据按一定批次组装数据，发送到mq
                this.handleMeterData(function, valueList);
            }
        }
        if (type == EquData.EquDataType.VALVE) {
            String houseValveSql = "select da.reason,da.state,da.planTime,da.readTime,da.equTime,da.workTime,da.settingTemperature,da.isLockTemperature," +
                    "da.settingOpening,da.isLockOpening,da.temperature,da.remainderHeat,da.controlType," +
                    "da.switchState,da.valveOpening,da.stateCode,da.supplyTemperature,da.returnTemperature," +
                    " equ.serialNo equNo,equ.index,ne.serialNo netNo from rcc_d_housevalvecurrentdata da " +
                    " inner join rcc_e_housevalve equ on equ.uniqueId = da.houseValveId " +
                    " inner join rcc_e_netequ ne on ne.uniqueId = equ.netEquId " +
                    " where ne.serialNo = '" + netEquNo + "' AND equ.serialNo = '" + equSerial + "'";
            logger.info("ValveSql语句为：" + houseValveSql);
            ArrayList<HashMap<String, Object>> valveDataList = mySqlJdbcUtil.query(houseValveSql);
            logger.info("valveDataList为：" + JSON.toJSONString(valveDataList));
            Map<String, List<HashMap<String, Object>>> valveByNetNo = valveDataList.stream().collect(Collectors.groupingBy(v -> String.valueOf(v.get("netNo"))));
            for (Map.Entry<String, List<HashMap<String, Object>>> entry : valveByNetNo.entrySet()) {
                String key = entry.getKey();
                //是否需要对没有网络设备的计量设备处理？因为对接的3.0系统，应该是没有主动上报的设备
                if ("null".equals(key)) {
                    logger.debug("没有找到网络设备编号" + JSONObject.toJSONString(entry.getValue()));
                    continue;
                }
                List<HashMap<String, Object>> valueList = entry.getValue();
                //同一个网络设备下的数据按一定批次组装数据，发送到mq
                this.handleValveData(function, valueList);
            }

            this.readPanelDate(function, netEquNo, equSerial);
        }
        if (type == EquData.EquDataType.PUBLIC_UNIT) {
//            String houseValveSql = "select da.reason,da.state,da.planTime,da.readTime,da.equTime,da.workTime,da.settingTemperature,da.isLockTemperature," +
//                    "da.settingOpening,da.isLockOpening,da.temperature,da.remainderHeat,da.controlType," +
//                    "da.switchState,da.valveOpening,da.stateCode,da.supplyTemperature,da.returnTemperature," +
//                    " equ.serialNo equNo,equ.index,ne.serialNo netNo from rcc_d_buildvalvecurrentdata da " +
//                    " inner join rcc_e_buildvalve equ on equ.uniqueId = da.buildValveId " +
//                    " inner join rcc_e_netequ ne on ne.uniqueId = equ.netEquId " +
//                    " where ne.serialNo = '" + netEquNo + "' AND equ.serialNo = '"+ equSerial + "'";
            String houseValveSql =
                    "select bv.serialNo,bvc.readTime,bvc.equTime,bvc.reason,bvc.actualOpening,bvc.actualValue,bvc.supplyTem,bvc.returnTem,bvc.supplyPre,bvc.behindPre,n.serialNo netNo\n" +
                            "FROM rcc_d_buildvalvecurrentdata bvc\n" +
                            "inner join rcc_e_buildvalve bv on bv.uniqueId = bvc.buildValveId  \n" +
                            "inner join rcc_e_netequ n on n.uniqueId = bv.netEquId  " +
                            " where n.serialNo = '" + netEquNo + "' AND bv.serialNo = '" + equSerial + "'";
            logger.info("ValveSql语句为：" + houseValveSql);
            ArrayList<HashMap<String, Object>> valveDataList = mySqlJdbcUtil.query(houseValveSql);
            logger.info("valveDataList为：" + JSON.toJSONString(valveDataList));
            Map<String, List<HashMap<String, Object>>> valveByNetNo = valveDataList.stream().collect(Collectors.groupingBy(v -> String.valueOf(v.get("netNo"))));
            for (Map.Entry<String, List<HashMap<String, Object>>> entry : valveByNetNo.entrySet()) {
                String key = entry.getKey();
                //是否需要对没有网络设备的计量设备处理？因为对接的3.0系统，应该是没有主动上报的设备
                if ("null".equals(key)) {
                    logger.debug("没有找到网络设备编号" + JSONObject.toJSONString(entry.getValue()));
                    continue;
                }
                List<HashMap<String, Object>> valueList = entry.getValue();
                //同一个网络设备下的数据按一定批次组装数据，发送到mq
                this.handleBuildValveData(function, valueList);
            }
        }
        if (type == EquData.EquDataType.TEMPERATURE_PANEL) {
            this.readPanelDate(function, netEquNo, equSerial);
        }
    }

    private void readPanelDate(TaskFunction function, String netEquNo, String equSerial) {
        String panelSql = "select tp.serialNo" +
                ",tpc.state,tpc.readTime,tpc.equTime,tpc.reason,tpc.temperature,tpc.panelCount,tpc.stateCode" +
                ",n.serialNo netNo " +
                ", tpcf.faultName " +
                "FROM rcc_d_temperaturepanelcurrentdata tpc " +
                "inner join rcc_e_temperaturepanel tp on tp.uniqueId = tpc.temperaturePanelId  " +
                "inner join rcc_e_netequ n on n.uniqueId = tp.netEquId " +
                "left join rcc_f_temperaturepanelcurrentfault tpcf on tpc.temperaturePanelId = tpcf.temperaturePanelId " +
                " where n.serialNo = '" + netEquNo + "' AND tp.serialNo = '" + equSerial + "'";
        logger.info("panelSql语句为：" + panelSql);
        ArrayList<HashMap<String, Object>> panelDataList = mySqlJdbcUtil.query(panelSql);
        logger.info("panelDataList为：" + JSON.toJSONString(panelDataList));
        Map<String, List<HashMap<String, Object>>> panelByNetNo = panelDataList.stream().collect(Collectors.groupingBy(v -> String.valueOf(v.get("netNo"))));
        for (Map.Entry<String, List<HashMap<String, Object>>> entry : panelByNetNo.entrySet()) {
            String key = entry.getKey();
            //是否需要对没有网络设备的计量设备处理？因为对接的3.0系统，应该是没有主动上报的设备
            if ("null".equals(key)) {
                logger.debug("没有找到网络设备编号" + JSONObject.toJSONString(entry.getValue()));
                continue;
            }
            List<HashMap<String, Object>> panelList = entry.getValue();
            logger.info("panelList为：" + JSON.toJSONString(panelList));
            //同一个网络设备下的数据按一定批次组装数据，发送到mq
            this.handlePanelData(function, panelList);
        }
    }

    @Resource
    private CommNetEquipmentService commNetEquipmentService;


//    @Scheduled(cron = "0 0/5 * * * ?")
    public void readAllPanel() {
        String panelSql = "select tp.serialNo" +
                ",tpc.state,tpc.readTime,tpc.equTime,tpc.reason,tpc.temperature,tpc.panelCount,tpc.stateCode" +
                ",n.serialNo netNo " +
                ", tpcf.faultName " +
                "FROM rcc_d_temperaturepanelcurrentdata tpc " +
                "inner join rcc_e_temperaturepanel tp on tp.uniqueId = tpc.temperaturePanelId  " +
                "inner join rcc_e_netequ n on n.uniqueId = tp.netEquId " +
                "left join rcc_f_temperaturepanelcurrentfault tpcf on tpc.temperaturePanelId = tpcf.temperaturePanelId " +
                "where tp.serialNo in ('03116952', '03010395')";
        logger.info("readAllPanel panelSql语句为：{}", panelSql);
        if (mySqlJdbcUtil == null) mySqlJdbcUtil = new MySqlJdbcUtil(tpzUrl, tpzUsername, tpzPassword);
        ArrayList<HashMap<String, Object>> panelDataList = mySqlJdbcUtil.query(panelSql);
        logger.info("readAllPanel panelDataList size {}", panelDataList.size());
        logger.debug("readAllPanel panelDataList {}", JSON.toJSONString(panelDataList));
        Map<String, List<HashMap<String, Object>>> panelByNetNo = panelDataList.stream().collect(Collectors.groupingBy(v -> String.valueOf(v.get("netNo"))));
        for (Map.Entry<String, List<HashMap<String, Object>>> entry : panelByNetNo.entrySet()) {
            String key = entry.getKey();
            //是否需要对没有网络设备的计量设备处理？因为对接的3.0系统，应该是没有主动上报的设备
            if ("null".equals(key)) {
                logger.debug("没有找到网络设备编号" + JSONObject.toJSONString(entry.getValue()));
                continue;
            }
            List<HashMap<String, Object>> panelList = entry.getValue();
            logger.debug("readAllPanel panelList {}", JSON.toJSONString(panelList));
            //同一个网络设备下的数据按一定批次组装数据，发送到mq
            List<PanelVO> panelVOList = this.handlePanelData(panelList);
            for (PanelVO panelVO : panelVOList) {
                AsynResult asynResult = AsynResult.success();
                if (panelVO.getSuccess()) {
                    asynResult.setContent(Collections.singletonList(panelVO));
                } else {
                    asynResult.unreadSetting();
                }
                CommPanel commPanel = commNetEquipmentService.getCommPanel(key, panelVO.getSerial());
                logger.debug("{} {} readAllPanel commPanel {}", key, panelVO.getSerial(), JSON.toJSONString(commPanel));
                if (null != commPanel) {
                    asynResult.setIdentity(commPanel.getId());
                    LogUtil.getLogAndInfo("panel", "抄3面板", "{} {}", PanelVO.TOPIC, asynResult);
                    MqttUtil.send(PanelVO.TOPIC, asynResult);
                } else {
                    LogUtil.getLogAndInfo("panel", "抄3面板", "{} {} 未找到", key, panelVO.getSerial());
                }
            }
        }
    }

    private void handlePanelData(TaskFunction function, List<HashMap<String, Object>> panelDataList) {
        List<PanelVO> panelVOList = handlePanelData(panelDataList);
        function.doApply(CommStatus.OK, panelVOList);
    }

    private List<PanelVO> handlePanelData(List<HashMap<String, Object>> panelDataList) {
        List<PanelVO> panelVOList = new ArrayList<>();
        for (HashMap<String, Object> dataMap : panelDataList) {
            Object state = dataMap.get("state");
            if (null == state) {
                logger.error("{} 抄通状态为空", JSON.toJSONString(dataMap));
                continue;
            }
            PanelVO panelVO = new PanelVO();
            panelVO.setSerial((String) dataMap.get("serialNo"));
            panelVO.setPanelType("温控");
            if (dataMap.get("readTime")!=null) panelVO.setReadTime((Date) dataMap.get("readTime"));
            if (dataMap.get("equTime")!=null) panelVO.setPanelDate((Date) dataMap.get("equTime"));

            Object faultNameObj = dataMap.get("faultName");
            List<String> faultList = new ArrayList<>();
            if (null != faultNameObj) {
                String faultName = String.valueOf(faultNameObj);
                if ("前后盖分离".equals(faultName)) {
                    faultList.add("面板分离");
                } else {
                    faultList.add(faultName);
                }
            }
            panelVO.setFaultCode(faultList);
            if (dataMap.get("temperature")!=null)panelVO.setTemperature(((BigDecimal) (dataMap.get("temperature"))).floatValue());
            if (dataMap.get("panelCount")!=null)panelVO.setCounter((Integer) dataMap.get("panelCount"));
            if (dataMap.get("stateCode")!=null) panelVO.setStatus((String) dataMap.get("stateCode"));
            Boolean b = Boolean.parseBoolean(String.valueOf(state));
            if (!b) {
                panelVO.setSuccess(false);
            }
            panelVOList.add(panelVO);
        }
        return panelVOList;
    }

    private void handleBuildValveData(TaskFunction function, List<HashMap<String, Object>> valveDataList) {
        function.doApply(CommStatus.OK, valveDataList.stream().map(dataMap -> {
            ValveVO valveVO = new ValveVO();
            valveVO.setValveSerial((String) dataMap.get("serialNo"));
            valveVO.setReadTime((Date) dataMap.get("readTime"));
            valveVO.setValveDate((Date) dataMap.get("equTime"));
//            valveVO.setActOpen(transformationToFloat(dataMap.get("valveOpening")));
            valveVO.setActOpen(((BigDecimal) (dataMap.get("actualOpening"))).floatValue());

//            valveVO.setRemoteSet(transformationToFloat(dataMap.get("settingOpening")));
            valveVO.setRemoteSet(((BigDecimal) (dataMap.get("actualValue"))).floatValue());
//            valveVO.setOpenLock((Boolean) dataMap.get("isLockOpening"));
//            valveVO.setOuputOpen(transformationToFloat(dataMap.get("settingOpening")));
//            valveVO.setTempLock((Boolean) dataMap.get("isLockTemperature"));
//            valveVO.setTempUL(transformationToFloat(dataMap.get("temperatureUp")));
//            valveVO.setTempDL(transformationToFloat(dataMap.get("temperatureDown")));
//            valveVO.setSupplyTemp(transformationToFloat(dataMap.get("supplyTemperature")));
            valveVO.setSupplyTemp(((BigDecimal) (dataMap.get("supplyTem"))).floatValue());
//            valveVO.setReturnTemp(transformationToFloat(dataMap.get("returnTemperature")));
            valveVO.setReturnTemp(((BigDecimal) (dataMap.get("returnTem"))).floatValue());
            valveVO.setSupplyPre(((BigDecimal) (dataMap.get("supplyPre"))).floatValue());
            valveVO.setBehindPre(((BigDecimal) (dataMap.get("behindPre"))).floatValue());

//            valveVO.setOpenTime(transformationToFloat(dataMap.get("workTime")));
            valveVO.setFaultCode((String) dataMap.get("reason"));
            if (valveVO.getFaultCode() != null && NetFaultCode.DEVICE_NOT_READ.getName().equalsIgnoreCase(valveVO.getFaultCode().get(0)))
                valveVO.setSuccess(false);
            logger.info("handleBuildValveData数据为：" + JSON.toJSONString(valveDataList));
            return valveVO;
        }).collect(Collectors.toList()));
    }


    private void handleValveData(TaskFunction function, List<HashMap<String, Object>> valveDataList) {
        function.doApply(CommStatus.OK, valveDataList.stream().map(dataMap -> {
            ValveVO valveVO = new ValveVO();
            valveVO.setValveSerial((String) dataMap.get("equNo"));
            valveVO.setReadTime((Date) dataMap.get("readTime"));
            valveVO.setValveDate((Date) dataMap.get("equTime"));
            if (dataMap.get("reason")!=null) valveVO.setFaultCode((String) dataMap.get("reason"));
            if (dataMap.get("workTime")!=null) valveVO.setOpenTime(((BigDecimal)(dataMap.get("workTime"))).floatValue());
//            if (dataMap.get("settingTemperature")!=null) valveVO.setRemoteSet(((BigDecimal)(dataMap.get("settingTemperature"))).floatValue());
            if (dataMap.get("isLockOpening")!=null) valveVO.setOpenLock((Boolean) dataMap.get("isLockOpening"));
            if (dataMap.get("settingOpening")!=null) valveVO.setRemoteSet(((BigDecimal)(dataMap.get("settingOpening"))).floatValue());
            if (dataMap.get("isLockTemperature")!=null) valveVO.setTempLock((Boolean) dataMap.get("isLockTemperature"));
            if (dataMap.get("temperatureUp")!=null) valveVO.setTempUL(((BigDecimal)(dataMap.get("temperatureUp"))).floatValue());
            if (dataMap.get("temperatureDown")!=null) valveVO.setTempDL(((BigDecimal)(dataMap.get("temperatureDown"))).floatValue());
            if (dataMap.get("valveOpening")!=null) valveVO.setActOpen(((BigDecimal)(dataMap.get("valveOpening"))).floatValue());
            if (dataMap.get("supplyTemperature")!=null) valveVO.setSupplyTemp(((BigDecimal)(dataMap.get("supplyTemperature"))).floatValue());
            if (dataMap.get("returnTemperature")!=null) valveVO.setReturnTemp(((BigDecimal)(dataMap.get("returnTemperature"))).floatValue());
            return valveVO;
        }).collect(Collectors.toList()));
    }


    private void handleMeterData(TaskFunction function, List<HashMap<String, Object>> meterDataList) {
        function.doApply(CommStatus.OK, meterDataList.stream().map(dataMap -> {
            HotMeterVO meter = new HotMeterVO();
            meter.setMeterSerial((String) dataMap.get("equNo"));
            meter.setReadDate((Date) dataMap.get("readTime"));
            meter.setMeterDate((Date) dataMap.get("equTime"));
            if (dataMap.get("state")!=null) meter.setSuccess((Boolean) dataMap.get("state"));
            if (dataMap.get("reason")!=null)meter.setFaultCode((String) dataMap.get("reason"));
            if (dataMap.get("flow")!=null)meter.setFlow(((BigDecimal)(dataMap.get("flow"))).floatValue());
            if (dataMap.get("heat")!=null)meter.setPower(((BigDecimal)(dataMap.get("heat"))).floatValue());
            if (dataMap.get("accFlow")!=null)meter.setAccFlow(((BigDecimal)(dataMap.get("accFlow"))).floatValue());
            if (dataMap.get("accHeat")!=null)meter.setAccHeat(((BigDecimal)(dataMap.get("accHeat"))).floatValue());
            if (dataMap.get("supplyTemperature")!=null)meter.setSupplyTemp(((BigDecimal)(dataMap.get("supplyTemperature"))).floatValue());
            if (dataMap.get("returnTemperature")!=null)meter.setReturnTemp(((BigDecimal)(dataMap.get("returnTemperature"))).floatValue());
            if (dataMap.get("workTime")!=null)meter.setWorkTime(transformationToFloat(dataMap.get("workTime")).intValue());
            if (dataMap.get("stateCode")!=null)meter.setStatus((String) dataMap.get("stateCode"));
            return meter;
        }).collect(Collectors.toList()));
    }


    private Float transformationToFloat(Object value) {
        return value == null ? null : Float.parseFloat((String) value);
    }
}
